/**
 * 
 */

package cinvestav.adviseme.databasemodel;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import cinvestav.adviseme.datamodel.Persona;
import cinvestav.adviseme.util.DBException;
import cinvestav.adviseme.util.DataBaseDictionary;

/**
 * 
 * @author Javier Silva Perez
 */
public class PersonaDB extends DataBase implements IPersonaDB {

	private static Logger log = Logger.getLogger(PersonaDB.class.getName());
	/**
	 * Constructor vacio
	 * 
	 * @throws DBException
	 */
	public PersonaDB() throws DBException {
		super();
		// TODO Auto-generated constructor stub
	}

	@Override
	public List<Persona> getAll() throws DBException {
		try {
			Connection c = this.getConnection();
			ResultSet res = this.ejecutarQuery(c
					.prepareStatement(DataBaseDictionary.GET_ALL_PERSONAS));
			List<Persona> personas= new LinkedList<Persona>();
			while (res.next()) {
				Persona persona = new Persona();
				persona.setId(res.getInt("ide_per"));
				persona.setNombrePersona(res.getString("nom_per"));
				persona.setApellidoPaterno(res.getString("app_per"));
				persona.setApellidoMaterno(res.getString("apm_per"));
				persona.setCorreo(res.getString("cor_per"));
				persona.setFechaNacimiento(res.getDate("fec_per"));
				persona.setFotografia(res.getString("fot_per"));
				persona.setNombreUsuario(res.getString("usu_per"));
				persona.setPassword(res.getString("pas_per"));
				persona.setSexo(res.getBoolean("sex_per"));
				persona.setSelected(Boolean.FALSE);
				personas.add(persona);
			}
			c.close();
			return personas;
		} catch (SQLException ex) {
			throw new DBException("Error al ejecutar la consulta:\n"
					+ DataBaseDictionary.GET_ALL_PERSONAS);
		}
	}

	@Override
	public List<Persona> getByFiter(Map<String, String[]> filtros)
			throws DBException {
		// TODO Auto-generated method stub
		try {
            //Se inicializa la coneccion
            //Se obtiene una nueva conexion
            Connection c = this.getConnection();
            //Se realiza la consulta
            ResultSet res = this.ejecutarQuery(genPreparedStatementString(filtros, c));
            //Procesamiento de resultados
            List<Persona> personas= new LinkedList<Persona>();
            //Por cada elemento en el resultSet, se genera una nueva linea y se
            //agrega a la lista
            while (res.next()) {
                //Los elementos del resultSet se obtienen a partir del nombre de la columna
                //O por su indice en la tabla
                Persona persona = new Persona();
                persona.setId(res.getInt("ide_per"));
				persona.setNombrePersona(res.getString("nom_per"));
				persona.setApellidoPaterno(res.getString("app_per"));
				persona.setApellidoMaterno(res.getString("apm_per"));
				persona.setCorreo(res.getString("cor_per"));
				persona.setFechaNacimiento(res.getDate("fec_per"));
				persona.setFotografia(res.getString("fot_per"));
				persona.setNombreUsuario(res.getString("usu_per"));
				persona.setPassword(res.getString("pas_per"));
				persona.setSexo(res.getBoolean("sex_per"));
				persona.setSelected(Boolean.FALSE);
                personas.add(persona);
            }
            c.close();
            return personas;
        } catch (SQLException ex) {
            Logger.getLogger(PersonaDB.class.getName()).log(Level.SEVERE, null, ex);
            throw new DBException("Error al ejecutar la consulta:\n" + ex.getMessage());
        } catch (DBException ex) {
            throw new DBException(ex);
        }
    }

    /**
     * Genera un PreparedStatement apartir de un Mapa de filtros y una coneccion
     * @param filtros   Mapa de filtros que se utilizaran para generar la consulta
     * @param c         Conexion que ejecutara el PreparedStatement
     * @return  Un preparedStatement listo para ser ejecutado
     */
    private PreparedStatement genPreparedStatementString(Map<String, String[]> filtros, Connection c) {

    	Boolean ini = Boolean.TRUE;
        //Se obtiene la consulta base
        //A esta cadena se le iran concatenando los filtros segun corresponda
        String statement = DataBaseDictionary.GET_BASE_PERSONAS;
        //SE obtiene el alias de la tabla a utilizar
        String alias = DataBaseDictionary.ALIAS_PERSONA;
        //Se recorre el mapa de filtros para generar el String de la consulta
        for (Map.Entry<String, String[]> entry : filtros.entrySet()) {
            //entry - Contiene la entrada del mapa una por una
            //Si NO es el primer elemento se agrega un AND a la consulla
            if (!ini) {
            	statement += " AND";
            } else {
            //Si es el primer filtro, se agrega la clausula WHERE a la consulta
                ini = Boolean.FALSE;
                statement += " WHERE ";
            }
            //Se agrega el filtro definido por el mapa
            statement += " " + alias + "." + entry.getKey();
        }

        //Una vez generada la cadena, se llenaran los datos del PreparedStatement '?'
        try {
            //Se inicializa el PreparedStatement y se liga este a la coneccion
            PreparedStatement ps = c.prepareStatement(statement);
            //llevara el indice de los elementos del ps, debe iniciar en 1
            int cont = 1;
            //Se recorre nuevamente el mapa de filtros
            for (Map.Entry<String, String[]> entry : filtros.entrySet()) {
                String[] val = entry.getValue();
                //Dependiendo del tipo de filtro, se agregan los valores al ps
                if (val[1].compareTo(DataBaseDictionary.STRING_SIMPLE) == 0) {
                    //Si es de tipo 'String_SIMPLE' es decir la busqueda se realiza con '='
                    ps.setString(cont, val[0]);
                } else if (val[1].compareTo(DataBaseDictionary.STRING_JOKER) == 0) {
                    //En este caso la busqueda se realiza con LIKE y se agrega el
                    //comodin de busqueda '%' al final del valor a buscar
                    ps.setString(cont, val[0] + "%");
                } else if (val[1].compareTo(DataBaseDictionary.STRING_DOBLE_JOKER) == 0) {
                    //En este caso la busqueda se realiza con LIKE y se agrega el
                    //comodin de busqueda '%' al final y al inicio del valor a buscar
                    ps.setString(cont, "%" + val[0] + "%");
                } else if (val[1].compareTo(DataBaseDictionary.INTEGER_TYPE) == 0) {
                    //Cuando el valor es entero
                    ps.setInt(cont, Integer.parseInt(val[0]));
                }
                cont++;
            }
            return ps;
        } catch (SQLException ex) {
            Logger.getLogger(PersonaDB.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }


	@Override
	public Boolean delete(Persona persona) throws DBException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Boolean insert(Persona persona) throws DBException {
		// TODO Auto-generated method stub
		try {

			// Se inicializa la coneccion
			// Se obtiene una nueva conexion
			Connection c = this.getConnection();
			// Si no, se procede a insertar la solicitud
			PreparedStatement ps = c
					.prepareStatement(DataBaseDictionary.INSERT_PERSONA);
			/*
			 * Se insertan los parametros al insert 
			 * [1] = Nombre de Usuario
			 * [2] = Nombre de pilar
			 * [3] = Apellido Paterno
			 * [4] = Apellido Materno 
			 * [5] = Correo electronico
			 * [6] = sexo
			 * [7] = fecha de nacimiento
			 * [8] = Foto de perfil
			 * [9] = password
			 */

			ps.setString(1, persona.getNombreUsuario());
			ps.setString(2, persona.getNombrePersona());
			ps.setString(3, persona.getApellidoPaterno());
			ps.setString(4, persona.getApellidoMaterno());
			ps.setString(5, persona.getCorreo());
			ps.setBoolean(6, persona.getSexo());
			ps.setDate(7, persona.getFechaNacimiento());
			ps.setString(8, persona.getFotografia());
			ps.setString(9, persona.getPassword());

			// Se realiza la consulta
			this.ejecutarInstruccion(ps);
			// Procesamiento de resultados
			c.close();
			return true;
		} catch (SQLException ex) {
			log.log(Level.SEVERE, null, ex);
			throw new DBException("Error al ejecutar la consulta:\n"
					+ ex.getMessage(), ex);
		}
	}

	@Override
	public List<Persona> getFriends(Persona personaFilter) throws DBException {
		try {
			Connection c = this.getConnection();
			PreparedStatement ps = c.prepareStatement(DataBaseDictionary.GET_BASE_FRIEND);
			ps.setInt(1, personaFilter.getId());
			ResultSet res = this.ejecutarQuery(ps);
			List<Persona> amigos= new LinkedList<Persona>();
			while (res.next()) {
				Persona persona = new Persona();
                persona.setId(res.getInt(DataBaseDictionary.ALIAS_AMIGO+".ide_per"));
				persona.setNombrePersona(res.getString(DataBaseDictionary.ALIAS_AMIGO+".nom_per"));
				persona.setApellidoPaterno(res.getString(DataBaseDictionary.ALIAS_AMIGO+".app_per"));
				persona.setApellidoMaterno(res.getString(DataBaseDictionary.ALIAS_AMIGO+".apm_per"));
				persona.setCorreo(res.getString(DataBaseDictionary.ALIAS_AMIGO+".cor_per"));
				persona.setFechaNacimiento(res.getDate(DataBaseDictionary.ALIAS_AMIGO+".fec_per"));
				persona.setFotografia(res.getString(DataBaseDictionary.ALIAS_AMIGO+".fot_per"));
				persona.setNombreUsuario(res.getString(DataBaseDictionary.ALIAS_AMIGO+".usu_per"));
				//persona.setPassword(res.getString(DataBaseDictionary.ALIAS_AMIGO+".pas_per"));
				persona.setSexo(res.getBoolean(DataBaseDictionary.ALIAS_AMIGO+".sex_per"));
				persona.setSelected(Boolean.FALSE);
                amigos.add(persona);
			}
			c.close();
			return amigos;
		} catch (SQLException ex) {
			throw new DBException("Error al ejecutar la consulta:\n"
					+ DataBaseDictionary.GET_BASE_FRIEND,ex);
		}
	}

	@Override
	public List<Persona> getFriendsByFilter(Persona personaFilter,
			Map<String, String[]> filtros) throws DBException {
		try {
            //Se inicializa la coneccion
            //Se obtiene una nueva conexion
            Connection c = this.getConnection();
            //Se realiza la consulta
            ResultSet res = this.ejecutarQuery(genPreparedStatementString(filtros, c,personaFilter.getId()));
            //Procesamiento de resultados
            List<Persona> amigos= new LinkedList<Persona>();
            //Por cada elemento en el resultSet, se genera una nueva linea y se
            //agrega a la lista
            while (res.next()) {
                //Los elementos del resultSet se obtienen a partir del nombre de la columna
                //O por su indice en la tabla
                Persona persona = new Persona();
                persona.setId(res.getInt(DataBaseDictionary.ALIAS_AMIGO+".ide_per"));
				persona.setNombrePersona(res.getString(DataBaseDictionary.ALIAS_AMIGO+".nom_per"));
				persona.setApellidoPaterno(res.getString(DataBaseDictionary.ALIAS_AMIGO+".app_per"));
				persona.setApellidoMaterno(res.getString(DataBaseDictionary.ALIAS_AMIGO+".apm_per"));
				persona.setCorreo(res.getString(DataBaseDictionary.ALIAS_AMIGO+".cor_per"));
				persona.setFechaNacimiento(res.getDate(DataBaseDictionary.ALIAS_AMIGO+".fec_per"));
				persona.setFotografia(res.getString(DataBaseDictionary.ALIAS_AMIGO+".fot_per"));
				persona.setNombreUsuario(res.getString(DataBaseDictionary.ALIAS_AMIGO+".usu_per"));
				//persona.setPassword(res.getString(DataBaseDictionary.ALIAS_AMIGO+".pas_per"));
				persona.setSexo(res.getBoolean(DataBaseDictionary.ALIAS_AMIGO+".sex_per"));
				persona.setSelected(Boolean.FALSE);
                amigos.add(persona);
            }
            c.close();
            return amigos;
        } catch (SQLException ex) {
            Logger.getLogger(PersonaDB.class.getName()).log(Level.SEVERE, null, ex);
            throw new DBException("Error al ejecutar la consulta:\n" + ex.getMessage());
        } catch (DBException ex) {
            throw new DBException(ex);
        }
	}
	
	/**
     * Genera un PreparedStatement apartir de un Mapa de filtros y una coneccion para la busqueda de amigos
     * @param filtros   Mapa de filtros que se utilizaran para generar la consulta
     * @param c         Conexion que ejecutara el PreparedStatement
     * @return  Un preparedStatement listo para ser ejecutado
     */
    private PreparedStatement genPreparedStatementString(Map<String, String[]> filtros, Connection c, Integer idPer) {

    	Boolean ini = Boolean.TRUE;
        //Se obtiene la consulta base
        //A esta cadena se le iran concatenando los filtros segun corresponda
        String statement = DataBaseDictionary.GET_BASE_FRIEND;
        //SE obtiene el alias de la tabla a utilizar
        String aliasAmigo = DataBaseDictionary.ALIAS_AMIGO;
        
        //Se recorre el mapa de filtros para generar el String de la consulta
        for (Map.Entry<String, String[]> entry : filtros.entrySet()) {
            //entry - Contiene la entrada del mapa una por una
            statement += " AND";
            //Se agrega el filtro definido por el mapa
            statement += " " + aliasAmigo + "." + entry.getKey();
        }

        //Una vez generada la cadena, se llenaran los datos del PreparedStatement '?'
        try {
            //Se inicializa el PreparedStatement y se liga este a la coneccion
            PreparedStatement ps = c.prepareStatement(statement);
            //llevara el indice de los elementos del ps, debe iniciar en 1
            int cont = 2;
            ps.setInt(1, idPer);
            //Se recorre nuevamente el mapa de filtros
            for (Map.Entry<String, String[]> entry : filtros.entrySet()) {
                String[] val = entry.getValue();
                //Dependiendo del tipo de filtro, se agregan los valores al ps
                if (val[1].compareTo(DataBaseDictionary.STRING_SIMPLE) == 0) {
                    //Si es de tipo 'String_SIMPLE' es decir la busqueda se realiza con '='
                    ps.setString(cont, val[0]);
                } else if (val[1].compareTo(DataBaseDictionary.STRING_JOKER) == 0) {
                    //En este caso la busqueda se realiza con LIKE y se agrega el
                    //comodin de busqueda '%' al final del valor a buscar
                    ps.setString(cont, val[0] + "%");
                } else if (val[1].compareTo(DataBaseDictionary.STRING_DOBLE_JOKER) == 0) {
                    //En este caso la busqueda se realiza con LIKE y se agrega el
                    //comodin de busqueda '%' al final y al inicio del valor a buscar
                    ps.setString(cont, "%" + val[0] + "%");
                } else if (val[1].compareTo(DataBaseDictionary.INTEGER_TYPE) == 0) {
                    //Cuando el valor es entero
                    ps.setInt(cont, Integer.parseInt(val[0]));
                }
                cont++;
            }
            return ps;
        } catch (SQLException ex) {
            Logger.getLogger(PersonaDB.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    
    
    
    
    public Boolean deleteFriendShip(Persona personaorigen, Persona personadestino) throws DBException{
    	try {
    		//Se inicializa la coneccion
            //Se obtiene una nueva conexion
            Connection c = this.getConnection();
            //Se realiza la consulta
            PreparedStatement ps = c.prepareStatement(DataBaseDictionary.DELETE_AMIGOS_POR_PERSONA);
            ps.setInt(1, personaorigen.getId());
            ps.setInt(2, personadestino.getId());
            
            this.ejecutarInstruccion(ps);
            c.close();
            return true;
		} catch (SQLException e) {
			// TODO: handle exception			
			Logger.getLogger(PersonaDB.class.getName()).log(Level.SEVERE, null, e);
            throw new DBException("Error al ejecutar la consulta:\n" + e.getMessage());            
		}    	
    }
    
    /**
     * Busca el usuario con el nombre de usuario indicado
     * @param userName  Nombre de usuario a buscar
     * @return  El usuario encontrado
     * @throws DBException
     */
    public Persona getByUserName(String userName) throws DBException {
        try {
            //Se pide una coneccion
            Connection c = this.getConnection();
            PreparedStatement ps = c.prepareStatement(DataBaseDictionary.GET_USER_BY_USERNAME);
            /*
             * Se insertan los parametros a la busqueda
             *  [1] = Nombre de usuario
             */
            ps.setString(1, userName);
            //Se realiza la busqueda en la base
            ResultSet res = this.ejecutarQuery(ps);
            //Se procesan los resultados de la consulta
            Persona persona = new Persona();
            if(res.next())
                persona = new Persona();
            	persona.setId(res.getInt(DataBaseDictionary.ALIAS_PERSONA+".ide_per"));
            	persona.setNombrePersona(res.getString(DataBaseDictionary.ALIAS_PERSONA+".nom_per"));
            	persona.setApellidoPaterno(res.getString(DataBaseDictionary.ALIAS_PERSONA+".app_per"));
				persona.setApellidoMaterno(res.getString(DataBaseDictionary.ALIAS_PERSONA+".apm_per"));
				persona.setCorreo(res.getString(DataBaseDictionary.ALIAS_PERSONA+".cor_per"));
				persona.setFechaNacimiento(res.getDate(DataBaseDictionary.ALIAS_PERSONA+".fec_per"));
				persona.setFotografia(res.getString(DataBaseDictionary.ALIAS_PERSONA+".fot_per"));
				persona.setNombreUsuario(res.getString(DataBaseDictionary.ALIAS_PERSONA+".usu_per"));
				persona.setPassword(res.getString(DataBaseDictionary.ALIAS_PERSONA+".pas_per"));
				persona.setSexo(res.getBoolean(DataBaseDictionary.ALIAS_PERSONA+".sex_per"));
				persona.setSelected(Boolean.FALSE);
            c.close();
            return persona;
        } catch (SQLException ex) {
            throw new DBException("Error al ejecutar la consulta:\n" + DataBaseDictionary.GET_USER_BY_USERNAME);
        }
    }

}
